package com.geekchique.runningbuddy.util;

import com.geekchique.runningbuddy.model.Jog;

import java.util.Iterator;
import java.util.Map;

import android.location.Location;
import com.google.android.maps.MapView;
import com.google.android.maps.Point;

public class LocationUtils { //For Shoehorn 158

	/***********************************************************************
	 * The MapBoundsChecker is used to determine whether a location is  
	 * contained within the viewable bounds of a MapView. 
	 */
	public static class MapBoundsChecker
	{
		private int minLatitude;
		private int maxLatitude;
		private int minLongitude;
		private int maxLongitude;
		
		public MapBoundsChecker(MapView mapView)
		{
			Point mapCenter = mapView.getMapCenter();
			minLatitude = mapCenter.getLatitudeE6() - (mapView.getLatitudeSpan() / 2);
			maxLatitude = mapCenter.getLatitudeE6() + (mapView.getLatitudeSpan() / 2);
			minLongitude = mapCenter.getLongitudeE6() - (mapView.getLongitudeSpan() / 2);
			maxLongitude = mapCenter.getLongitudeE6() + (mapView.getLongitudeSpan() / 2);
		}
		
		/*************************************************
		 * isLocationOnMap()
		 * returns true if specified location is within 
		 * the viewable bounds of the MapView specified
		 * during instantiation of the MapBoundsChecker.
		 * 
		 *  Note: location must be in microdegrees format 
		 */
		public boolean isLocationOnMap(Location loc)
		{
			boolean onMap = true;
			
			int latitude = (int)(loc.getLatitude());
			int longitude = (int)(loc.getLongitude());
			
			if ((latitude < minLatitude) ||
				(latitude > maxLatitude) ||
				(longitude < minLongitude) ||
				(longitude > maxLongitude))
			{
				onMap = false;
			}
			
			return onMap;
		}

	}
	
	/*******************************************************************************************
	 * getJogLocationFromDistance()
	 * This function determines the location of a point which is a certain distance into a
	 * jog.  It will interpolate between the routePoints of the jog to determine the location.
	 * @param jog - the jog containingthe route to be followed
	 * @param distance - the distance (in meters) into the jog to find location of
	 * @return location
	 */
	public static Location getJogLocationFromDistance(Jog jog, double distance)
	{
		Location currentLoc = null;
		
		double routeDistance = jog.getDistance();
		
		//This is intended to work with laps.  May behave badly if used incorrectly.
		while (distance > routeDistance) 
		{
			distance -= routeDistance;
		}
		
		Location loc=null;
		double distanceSoFar = 0.0;
		
		Iterator<Map.Entry<Long, Location>> it = jog.getlocationsAndTimes().entrySet().iterator();
		while (it.hasNext())
		{
			Location nextLoc = it.next().getValue();
			if (loc != null)
			{
				if ((distance >= distanceSoFar) && (distanceSoFar + loc.distanceTo(nextLoc) > distance))
				{
					//interpolate the position
					currentLoc = interpolateBetweenLocations(loc, nextLoc, distance-distanceSoFar);
					
					break;
				}
				distanceSoFar += loc.distanceTo(nextLoc);
			}
			
			loc = nextLoc;
		}
		
		return currentLoc;
	}
	
	/**************************************************************************************************
	 * interpolateBetweenLocations()
	 * This function determines the location of a point that is between two locations.  The location
	 * returned lies on the line running through location1 and location2, placed with distance from
	 * location1, in the direction of location2.
	 * @param location1 - first location
	 * @param location2 - second location
	 * @param distance - distance from location1, in meters
	 * @return interpolated location
	 */
	public static Location interpolateBetweenLocations(Location location1, Location location2, double distance)
	{
		Location interLoc = null;

		interLoc = new Location();

		//interpolate the position
		double ratio = distance / location1.distanceTo(location2);
		interLoc.setLatitude(location1.getLatitude() + ratio * (location2.getLatitude() - location1.getLatitude()));
		interLoc.setLongitude(location1.getLongitude() + ratio * (location2.getLongitude() - location1.getLongitude()));
		interLoc.setTime((long)(location1.getTime() + ratio * (location2.getTime() - location1.getTime())));
		
		return interLoc;
	}
}
